package org.video.mine.mycode;

import android.content.Context;
import android.os.Environment;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import org.greenrobot.eventbus.EventBus;
import org.video.mine.GlobalStr;
import org.video.mine.MyPreference;
import org.video.mine.entity.AlreadyLoadOkEntity;
import org.video.mine.entity.LoadedEntity;
import org.video.mine.entity.LoadingEntity;
import org.video.mine.event.DownLoadOkEvent;
import org.video.mine.event.LoadErrorEvent;
import org.video.mine.event.LoadFailedEvent;
import org.video.mine.event.NotifyLoadingPro;
import org.video.mine.network.JsoupGet;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class DownThread extends Thread{

    public String set;
    public String url;
    public String name;
    public boolean isStarted= false;
    private boolean failed = false;
    private int tryCount = 0;
    private String imgUrl;
    List<File> saveFiles = new ArrayList<>();
    private Context context;
    private MyPreference preference;
    public boolean isLoading = false;
    private String key="";
    private String method="";
    private String iv="";
    private boolean isByte=false;
    private byte[] keyBytes = new byte[16];

    public DownThread(String url, String name, String set, Context context, String imgUrl) {
        this.url = url;
        if (name.length()>10){
            this.name = name.substring(0,10);
        }else {
            this.name = name;
        }
        this.name = GlobalStr.returnName(this.name);
        this.set = set;
        this.context = context;
        this.imgUrl = imgUrl;
    }

    @Override
    public void run() {
        File saveFile1 = new File(GlobalStr.getSDPath(context), name + "/" + set + GlobalStr.saveType);
        if (saveFile1.exists()){
            AlreadyLoadOkEntity alreadyLoadOkEntity = new AlreadyLoadOkEntity();
            alreadyLoadOkEntity.setImgUrl(imgUrl);
            alreadyLoadOkEntity.setName(name);
            preference = MyPreference.getInstance();
            preference.setPreference(context);

            List<LoadingEntity> getLoading = (List<LoadingEntity>) preference.getObject(MyPreference.loading, LoadingEntity.class);
            for (LoadingEntity loadingEntity : getLoading) {
                if (loadingEntity.getName().equals(name) && loadingEntity.getSet().equals(set)) {
                    getLoading.remove(loadingEntity);
                    break;
                }
            }
            preference.setObject(MyPreference.loading, getLoading);

            List<AlreadyLoadOkEntity> loadOkEntities = (List<AlreadyLoadOkEntity>) preference.getObject(MyPreference.loadok, AlreadyLoadOkEntity.class);
            if (loadOkEntities == null) {
                loadOkEntities = new ArrayList<>();
            }
            boolean isHave = false;
            for (AlreadyLoadOkEntity loadOkEntity : loadOkEntities) {
                if (loadOkEntity.getName().equals(name)) {
                    if (!TextUtils.isEmpty(loadOkEntity.getImgUrl())) {
                        isHave = true;
                    }else {
                        loadOkEntities.remove(loadOkEntity);
                    }
                    break;
                }
            }
            if (!isHave) {
                loadOkEntities.add(alreadyLoadOkEntity);
                preference.setObject(MyPreference.loadok, loadOkEntities);
            }
            EventBus.getDefault().post(new DownLoadOkEvent(name,set));
        }else {
            List<List> tsLists = JsoupGet.getTs(url);
            if (tsLists.size()>2){
                List<HashMap> listmap = (List<HashMap>) tsLists.get(2);
                if (listmap.size()>0) {
                    HashMap map = listmap.get(0);
                    key = (String) map.get("key");
                    method = (String) map.get("method");
                    iv = (String) map.get("iv");
                    isByte = false;
                    keyBytes = new byte[16];

                    if (!TextUtils.isEmpty(key)) {
                        String relativeUrl = url.substring(0, url.lastIndexOf("/") + 1);
                        key = key.replace("\"", "");
                        HashMap keyMap = JsoupGet.getUrlContent(GlobalStr.isUrl(key) ? key : relativeUrl + key, true);
                        isByte = (boolean) keyMap.get("isByte");
                        keyBytes = (byte[]) keyMap.get("keyBytes");
                    }
                }
            }
            String homeUrl = url.substring(0, url.indexOf(".m3u8"));
            int index = 0;
            tryCount = 0;
            saveFiles.clear();
            isStarted = true;
            if (tsLists.size()>0) {
                while (index < tsLists.get(0).size() &&  tryCount<10 && isLoading) {
                    isLoading = true;
                    failed = false;
                    Log.d("tryCount=",tryCount+",index="+index);
                    long startTime = System.currentTimeMillis();
                    String tsUrl1 = (String) tsLists.get(0).get(index);
                    String newHome = homeUrl.replace("//", "/");
                    String[] homeSplite = newHome.split("/");
                    String[] tsUrls = tsUrl1.split("/");
                    String tsUrl = "";
                    List<String> homeLists = Arrays.asList(homeSplite);
                    if (tsUrls.length>1 && homeLists.contains(tsUrls[1])){
                        int tsIndex = homeLists.indexOf(tsUrls[1]);
                        tsUrl = homeUrl.substring(0, homeUrl.indexOf(homeSplite[tsIndex])) + "/" + tsUrl1;
                    } else {
                        tsUrl = (String) tsLists.get(0).get(index);
                        tsUrl = tsUrl.startsWith("http")? tsUrl :(homeUrl + (String) tsLists.get(0).get(index));
                    }
                    File tempDir = new File(GlobalStr.getSDPath(context), name + "/temp/" + set);
                    if (!tempDir.exists()) {
                        tempDir.mkdirs();
                    }
                    String type = tsUrl.substring(tsUrl.lastIndexOf("."),tsUrl.length());
                    File writeFile = new File(GlobalStr.getSDPath(context), name + "/temp/" + set + "/" + index + ".ts");
                    if (!writeFile.exists()) {
                        FileOutputStream outputStream = null;
                        InputStream inputStream = null;
                        try {
                            URL url = new URL(tsUrl);
                            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
                            httpURLConnection.setConnectTimeout((int) 50000);
                            httpURLConnection.setUseCaches(false);
                            httpURLConnection.setReadTimeout((int) 10000);
                            httpURLConnection.setDoInput(true);
                            inputStream = httpURLConnection.getInputStream();
                            byte[] bytes = new byte[1024];
                            if (!isLoading)
                                break;
                            outputStream = new FileOutputStream(writeFile);
                            int len;
                            //将ts片段写入文件
                            while ((len = inputStream.read(bytes)) != -1) {
                                outputStream.write(bytes, 0, len);
                            }
                            outputStream.flush();
                            inputStream.close();
                            if (!TextUtils.isEmpty(key)) {
                                FileInputStream inputStream1 = new FileInputStream(writeFile);
                                byte[] bytes1 = new byte[inputStream1.available()];
                                inputStream1.read(bytes1);
                                File file = new File(GlobalStr.getSDPath(context), name + "/temp/" + set + "/" + index + ".ts");
                                FileOutputStream outputStream1 = new FileOutputStream(file);
                                //开始解密ts片段，这里我们把ts后缀改为了xyz，改不改都一样
                                outputStream1.write(decrypt(bytes1, key, iv, method));
                                inputStream1.close();
                                outputStream1.flush();
                            }

                            saveFiles.add(writeFile);
                            tryCount=0;
                            if (System.currentTimeMillis() - startTime > 500) {
                                startTime = System.currentTimeMillis();
                                EventBus.getDefault().post(new NotifyLoadingPro(name, set));
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                            failed = true;
                        } finally {
                            try {
                                if (outputStream != null) {
                                    outputStream.close();
                                }
                                if (inputStream != null) {
                                    inputStream.close();
                                }
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    } else {
                        saveFiles.add(writeFile);
                    }
                    if(!failed) {
                        tryCount=0;
                        index++;
                    }else {
                        tryCount++;
                    }
                }
                if (failed){
                    EventBus.getDefault().post(new LoadErrorEvent(name, set));
                    EventBus.getDefault().post(new LoadFailedEvent(name + set + "   下载出错，请重试"));
                }
                if (isLoading) {
                    if (saveFiles.size() == tsLists.get(0).size()) {
                        try {
                            File saveFile = new File(GlobalStr.getSDPath(context), name + "/" + set + GlobalStr.saveType);
                            if (saveFile.exists())
                                saveFile.delete();
                            FileOutputStream fileOutputStream = new FileOutputStream(saveFile);
                            byte[] b = new byte[4096];
                            Collections.sort(saveFiles, new Comparator<File>() {
                                @Override
                                public int compare(File o1, File o2) {
                                    if (Integer.parseInt(o1.getName().replace(".ts", "")) > Integer.parseInt(o2.getName().replace(".ts", ""))) {
                                        return 1;
                                    } else {
                                        return -1;
                                    }
                                }
                            });
                            for (File f : saveFiles) {
                                FileInputStream fileInputStream = new FileInputStream(f);
                                int len;
                                while ((len = fileInputStream.read(b)) != -1) {
                                    fileOutputStream.write(b, 0, len);
                                }
                                fileInputStream.close();
                                fileOutputStream.flush();
                            }
                            fileOutputStream.close();
                        } catch (Exception e) {
                            e.printStackTrace();
                            EventBus.getDefault().post(new LoadErrorEvent(name, set));
                            EventBus.getDefault().post(new LoadFailedEvent(name + set + "   下载出错，请重试"));
                        }
                        File file = new File(GlobalStr.getSDPath(context), name + "/temp/" + set + "/");
                        for (File f : file.listFiles()) {
                            f.delete();
                        }
                        file.delete();
                        AlreadyLoadOkEntity alreadyLoadOkEntity = new AlreadyLoadOkEntity();
                        alreadyLoadOkEntity.setImgUrl(imgUrl);
                        alreadyLoadOkEntity.setName(name);
                        preference = MyPreference.getInstance();
                        preference.setPreference(context);

                        List<LoadingEntity> getLoading = (List<LoadingEntity>) preference.getObject(MyPreference.loading, LoadingEntity.class);
                        for (LoadingEntity loadingEntity : getLoading) {
                            if (loadingEntity.getName().equals(name) && loadingEntity.getSet().equals(set)) {
                                getLoading.remove(loadingEntity);
                                break;
                            }
                        }
                        preference.setObject(MyPreference.loading, getLoading);

                        List<AlreadyLoadOkEntity> loadOkEntities = (List<AlreadyLoadOkEntity>) preference.getObject(MyPreference.loadok, AlreadyLoadOkEntity.class);
                        if (loadOkEntities == null) {
                            loadOkEntities = new ArrayList<>();
                        }
                        boolean isHave = false;
                        for (AlreadyLoadOkEntity loadOkEntity : loadOkEntities) {
                            if (loadOkEntity.getName().equals(name)) {
                                if (!TextUtils.isEmpty(loadOkEntity.getImgUrl())) {
                                    isHave = true;
                                } else {
                                    loadOkEntities.remove(loadOkEntity);
                                }
                                break;
                            }
                        }
                        if (!isHave) {
                            loadOkEntities.add(alreadyLoadOkEntity);
                            preference.setObject(MyPreference.loadok, loadOkEntities);
                        }
                        EventBus.getDefault().post(new DownLoadOkEvent(name, set));
                        DownTask.loadReady(name, set);
                    } else {
                        EventBus.getDefault().post(new LoadErrorEvent(name, set));
                        EventBus.getDefault().post(new LoadFailedEvent(name + set + "   下载出错，请重试"));
                    }
                    isStarted = false;
                } else {
                    EventBus.getDefault().post(new LoadFailedEvent(name + set + "   暂停下载"));
                }
            }else {
                EventBus.getDefault().post(new LoadErrorEvent(name, set));
                EventBus.getDefault().post(new LoadFailedEvent(name + set + "   下载失败"));
            }
        }
    }



    /**
     * 解密ts
     *
     * @param sSrc ts文件字节数组
     * @param sKey 密钥
     * @return 解密后的字节数组
     */
    private byte[] decrypt(byte[] sSrc, String sKey, String iv, String method) throws Exception {
        if (!TextUtils.isEmpty(method) && !method.contains("AES")) {
            throw new Exception("未知的算法！");
        }
        // 判断Key是否正确
        if (TextUtils.isEmpty(sKey)) {
            return sSrc;
        }
        // 判断Key是否为16位
        if (sKey.length() != 16 && !isByte) {
            System.out.print("Key长度不是16位");
            throw new Exception("未知的算法！");
        }
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        SecretKeySpec keySpec = new SecretKeySpec(isByte ? keyBytes : sKey.getBytes("utf-8"), "AES");
        byte[] ivByte;
        if (iv.startsWith("0x"))
            ivByte = hexStringToByteArray(iv.substring(2));
        else ivByte = iv.getBytes();
        if (ivByte.length != 16)
            ivByte = new byte[16];
        //如果m3u8有IV标签，那么IvParameterSpec构造函数就把IV标签后的内容转成字节数组传进去
        AlgorithmParameterSpec paramSpec = new IvParameterSpec(ivByte);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, paramSpec);
        return cipher.doFinal(sSrc);
    }

    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }

}
